home *** CD-ROM | disk | FTP | other *** search
/ Programming Sound Cards / Programming Sound Cards.iso / sound_64 / dma_code.asm < prev    next >
Assembly Source File  |  1995-01-01  |  15KB  |  337 lines

  1.                 IDEAL
  2.                 ModeL large
  3.  
  4. ;+---------------------------------------------------------------------------+
  5. ;|  IBM-PC(tm) compatible programmer's DMA library                           |
  6. ;|  Version 1.1                                                              |
  7. ;+---------------------------------------------------------------------------+
  8. ;|  Copyright (C) 1992, Heath I Hunnicutt                                    |
  9. ;+---------------------------------------------------------------------------+
  10. ;|  Thanks to: Gary Nemirovsky                                               |
  11. ;+---------------------------------------------------------------------------+
  12. ;|  This document is for free public distribution.  It is unlawful to        |
  13. ;|  sell this document, or any work based substantially upon it.             |
  14. ;+---------------------------------------------------------------------------+
  15. ;|  This assembly code defines 3 functions that are intended for use         |
  16. ;|  by C programmers in code that requires access to the DMA system.         |
  17. ;|                                                                           |
  18. ;|  DMA transfers occur asynchronously to the CPU's activity, so they        |
  19. ;|  are quite efficient.                                                     |
  20. ;|                                                                           |
  21. ;|  The general sequence for using the DMA is:                               |
  22. ;|      int channel=1;                                                       |
  23. ;|      if (dma_reset(channel))                                              |
  24. ;|              abort();                                                     |
  25. ;|      if (dma_setup(channel,(char far *)My_Buffer,sizeof(My_Buffer),1))    |
  26. ;|              abort();                                                     |
  27. ;|      /* Insert "foreground" code here. */                                 |
  28. ;|      while (dma_done(channel)!=-1) {                                      |
  29. ;|              if (dma_errno)                                               |
  30. ;|                      abort();                                             |
  31. ;|      }                                                                    |
  32. ;+---------------------------------------------------------------------------+
  33. ;| Send suggestions, questions, comments, knoweledge to:                     |
  34. ;|          heathh@cco.caltech.edu     (also @tybalt.cco.caltech.edu)        |
  35. ;|          (or hihunn@through.ugcs.caltech.edu  -- not preferred)           |
  36. ;+---------------------------------------------------------------------------+
  37. ;| PUBLIC FUNCTIONS                                                          |
  38. ;| int far dma_reset(int Channel)                                            |
  39. ;| int far dma_setup(int Channel,char far *Buffer,unsigned Length,int Dir)   |
  40. ;| int far dma_done(int Channel)                                             |
  41. ;+---------------------------------------------------------------------------+
  42. ;| PUBLIC DATA                                                               |
  43. ;| int far dma_errno                                                         |
  44. ;| char far *dma_errlist[]                                                   |
  45. ;+---------------------------------------------------------------------------+
  46. ;| How to assemble this code:                                                |
  47. ;|      You'll need Turbo Assembler(tm) from Borland(tm) Internationl        |
  48. ;| TASM /mx /m2 dma_code                                                     |
  49. ;+---------------------------------------------------------------------------+
  50. ;| HISTORY:                                                                  |
  51. ;|   Ver 1.0 - Initial Release                                               |
  52. ;|   Ver 1.1 - Error checking and reporting added to all functions           |
  53. ;|             dma_setup(..) should never crash your system now.             |
  54. ;+---------------------------------------------------------------------------+
  55.  
  56. Status          EQU     08h     ;DMAC status port (read)     \  same port
  57. Command         EQU     08h     ;DMAC command port (write)   /  (read/write)
  58. ;STATUS/COMMAND BYTE:   ("*" represents defaults)
  59. ;  [ 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 ]
  60. ;   Bit 0: Memory-to-memory transfer  0 => disable*
  61. ;                                     1 => enable
  62. ;       1: "Don't Care" if mem-to-mem disabled  (Bit 0==0)*
  63. ;          Channel 0 address hold     0 => disable
  64. ;                                     1 => enable
  65. ;       2: Controller enable          0 => enable*
  66. ;                                     1 => disable
  67. ;       3: "Don't Care" if mem-to-mem enabled (Bit 0==1)
  68. ;          Timing                     0 => Normal?
  69. ;                                     1 => Compressed?
  70. ;       4: Priority                   0 => Fixed?
  71. ;                                     1 => Rotating
  72. ;       5: "Don't care" if compressed timing (Bit 3==1)
  73. ;          Write selection            0 => Late
  74. ;                                     1 => Extended
  75. ;       6: DREQ sense active          0 => High
  76. ;                                     1 => Low
  77. ;       7: DACK sense active          0 => Low
  78. ;                                     1 => High
  79.  
  80. Request         EQU     09h     ;DMAC channel request (write-only)
  81. ;REQUEST BYTE:
  82. ;  [ 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 ]
  83. ;  \__________________/  |  \_____/
  84. ;       Don't care       |     |
  85. ;                        |     +------+  00 = Select channel 0
  86. ;                        |            |  01 = Select channel 1
  87. ;                        |            |  10 = Select channel 2
  88. ;                        |            +  11 = Select channel 3
  89. ;                        +---+ 0 = Reset request bit
  90. ;                            + 1 = Set request bit
  91.  
  92. DMA_Mask        EQU     0Ah     ;DMAC DMA_Mask (write-only)
  93. Mode            EQU     0Bh     ;DMAC mode (read/write)
  94.  
  95.  
  96. byte_ptr        EQU     00ch    ; byte pointer flip-flop
  97.  
  98. addr               EQU    000h    ; per-channel base address
  99. count               EQU    001h    ; per-channel byte count
  100.  
  101. read_cmd        EQU     048h    ; read mode
  102. write_cmd       EQU     044h    ; write mode
  103. set_cmd         EQU     000h    ; DMA_Mask set
  104. reset_cmd       EQU     004h    ; DMA_Mask reset
  105.  
  106. ; dma controller page register table
  107. ; this table maps from channel number to the i/o port number of the
  108. ; page register for that channel
  109.                 DATASEG
  110.  
  111. page_table         DW    00087h    ; channel 0
  112.                DW    00083h    ; channel 1
  113.                DW    00081h    ; channel 2
  114.                  DW    00082h    ; channel 3
  115.  
  116. ; "Extra" messages are for future compatability with the Virtual DMA
  117. ; specification.
  118. DMA_E0          DB      0
  119. DMA_E1          DB      "Region not in contiguous memory.",0
  120. DMA_E2          DB      "Region crossed a physical alignment boundary.",0
  121. DMA_E3          DB      "Unable to lock pages.",0
  122. DMA_E4          DB      "No buffer available.",0
  123. DMA_E5          DB      "Region too large for buffer.",0
  124. DMA_E6          DB      "Buffer currently in use.",0
  125. DMA_E7          DB      "Invalid memory region.",0
  126. DMA_E8          DB      "Region was not locked.",0
  127. DMA_E9          DB      "Number of physical pages greater than table length.",0
  128. DMA_EA          DB      "Ivalid buffer ID.",0
  129. DMA_EB          DB      "Copy out of buffer range.",0
  130. DMA_EC          DB      "Invalid DMA channel number.",0
  131. _dma_errlist DD DMA_E0, DMA_E1, DMA_E2, DMA_E3, DMA_E4, DMA_E5, DMA_E6, DMA_E7, DMA_E8, DMA_E9, DMA_EA, DMA_EB, DMA_EC
  132. _dma_errno   DW 0
  133.  
  134. ;char far *dma_errlist[]
  135. ;int _dma_errno
  136. PUBLIC _dma_errlist,_dma_errno
  137.  
  138.                 CODESEG
  139. MACRO zero reg
  140.       xor reg,reg
  141. ENDM zero
  142.       
  143. PUBLIC _dma_setup,_dma_reset,_dma_done
  144. ;+---------------------------------------------------------------------------+
  145. ;| int far dma_setup(int Channel,char far *Buffer,unsigned Length,int Dir)   |
  146. ;| ------------------------------------------------------------------------- |
  147. ;| Channel = 0-3  !Channel 0 is often reserved for memory refresh!           |
  148. ;| Buffer  = Address of data to transfer                                     |
  149. ;| Length  = Length of data to transfer                                      |
  150. ;| Dir     = Direction to move bytes.  1 == Out to the BUS (TO the card)     |
  151. ;|                                     0 == In from the BUS and cards.       |
  152. ;| ------------------------------------------------------------------------- |
  153. ;| Returns: 0 if no errors (dma_errno == 0)                                  |
  154. ;|         -1 if errors occured (dma_errno set to indicate error.)           |
  155. ;+---------------------------------------------------------------------------+
  156. PROC _dma_setup FAR
  157. ARG Channel:WORD,Buffer:DWORD,Len:WORD,Dir:WORD
  158.     push bp
  159.     mov  bp,sp
  160.         push bx cx dx si di
  161.     pushf
  162.  
  163.         mov  [_dma_errno],0
  164. ;Convert seg:ofs Buffer to 20-bit physical address
  165. ;Assumes operating in 8086/real-Mode
  166.         mov  bx,[WORD PTR Buffer]
  167.         mov  ax,[WORD PTR Buffer+2]
  168.     mov  cl,4
  169.         rol  ax,cl
  170.         mov  ch,al
  171.         and  al,0F0h
  172.         add  ax,bx
  173.         adc  ch,0
  174.         and  ch,0Fh
  175.         mov  di,ax
  176. ; (ch << 16) + di == The physical buffer base.
  177.  
  178. ;Calculate the port to receive this address
  179.         mov  bx,[Channel]
  180.         cmp  bx,3
  181.          jbe @@OkChannel
  182.         mov  [_dma_errno],0Ch
  183.         mov  ax,-1
  184.          jmp @@ExitPt
  185. @@OkChannel:
  186.         shl  bx,1
  187. ;bx == Port # Channel*2
  188.  
  189. ;Determine which command byte will be written later
  190.         cmp  [WORD PTR Dir],0
  191.          jnz SHORT @@Do_Read
  192.         mov  al,write_cmd
  193.          jmp SHORT @@Do_Mode
  194. @@Do_Read:
  195.       mov  al,read_cmd
  196. @@Do_Mode:
  197.         push cx
  198.         mov  cx,[Channel]
  199.       add  al,cl
  200.         zero ah
  201.         mov  si,ax
  202.         mov  ax,set_cmd
  203.         add  al,cl
  204.         pop  cx
  205.         mov  cl,al
  206. ;si contains READ/WRITE command for DMA controller
  207. ;cl contains confirmation command for DMA controller
  208.  
  209. ;-------------------------------------------------------------------------
  210. ; Calculations have been done ahead of time to minimize time with
  211. ; interrupts disabled.
  212. ;
  213. ; ch:di == physical base address
  214. ;
  215. ; cl == Confirmation command    (Tells DMA we're done bothering it.)
  216. ;
  217. ; bx == I/O port Channel*2      (This is where the address is written)
  218. ;
  219. ; si == Mode command for DMA
  220. ;-------------------------------------------------------------------------
  221.         mov  ax,di              ;Let's check the address to see if we
  222.         add  ax,[Len]           ;span a page boundary with our length
  223.          jnc @@BoundaryOk       ;Do we?
  224.         mov  [_dma_errno],2     ; y: Error #2
  225.         mov  ax,-1              ;    Return -1
  226.          jmp @@ExitPt           ;    See ya...
  227. @@BoundaryOk:                   ; n: Continue with action
  228.         cli                     ;Disable interrupts while mucking with DMA
  229.  
  230. ;The "byte pointer" is also known as the LSB/MSB flip flop.
  231. ;By writing any value to it, the DMA controller registers are prepared
  232. ;to accept the address and length values LSB first.
  233.         mov  dx,byte_ptr        ;Reset byte pointer Flip/flop
  234.         out  dx,al              ;All we have to do is write to it
  235.  
  236.         mov  ax,di              ;ax=LSW of 20-bit address
  237.         mov  dx,bx              ;dx=DMAC Base Address port
  238.     out  dx,al              ;Store LSB
  239.         mov  al,ah
  240.         out  dx,al              ;Store next byte
  241.  
  242.         mov  al,ch              ;al=Page number
  243.         mov  dx,[bx + OFFSET page_table]        ;dx=Port is the "Page index"
  244.         out  dx,al              ;Store the page
  245.  
  246. ;Write length to port Channel*2 + 1
  247.         mov  ax,[Len]
  248.         mov  dx,bx              ;dx=DMAC Base Adress port
  249.         inc  dx                 ;dx=DMAC Count port (1 after Base address)
  250.         out  dx,al              ;Write LSB of Length
  251.         mov  al,ah
  252.         out  dx,al              ;Write MSB
  253.  
  254.         mov  ax,si              ;Load pre-calculated mode
  255.         mov  dx,Mode            ;dx=DMAC mode register
  256.         out  dx,al              ;Write it to the DSP
  257.  
  258.         mov  dx,DMA_Mask        ;dx=DMAX DMA_Mask register
  259.         mov  al,cl              ;al=pre-calulated DMA_Mask value
  260.         out  dx,al              ;Write DMA_Mask
  261.         mov  ax,0               ;Return with no error
  262.  
  263. @@ExitPt:                       ;Restore stack and return
  264.         popf
  265.         pop  di si dx cx bx
  266.         pop  bp
  267.         ret
  268. ENDP _dma_setup                    
  269.  
  270. ;+---------------------------------------------------------------------------+
  271. ;| int far dma_reset(int Channel)                                            |
  272. ;| ------------------------------------------------------------------------- |
  273. ;| Channel = 0-3                                                             |
  274. ;|         Resets the specified channel.                                     |
  275. ;| ------------------------------------------------------------------------- |
  276. ;| Returns 0 if Ok, -1 and sets dma_errno on error                           |
  277. ;+---------------------------------------------------------------------------+
  278. PROC _dma_reset FAR
  279. ARG Channel:Word
  280.     push bp
  281.         mov  bp,sp
  282.         push dx
  283.         mov  [_dma_errno],0
  284.         cmp  [Channel],3
  285.          jbe @@OkChannel
  286.         mov  [_dma_errno],0Ch
  287.         mov  ax,-1
  288.          jmp @@Exit_Pt
  289. @@OkChannel:
  290.         mov  dx,DMA_Mask
  291.         mov  ax,reset_cmd
  292.         add  ax,[Channel]
  293.         out  dx,al
  294.         mov  ax,0
  295. @@Exit_Pt:
  296.         pop  dx
  297.         pop  bp
  298.         ret
  299. ENDP _dma_reset
  300.  
  301. ;+---------------------------------------------------------------------------+
  302. ;| int far dma_done(Channel)                                                 |
  303. ;| ------------------------------------------------------------------------- |
  304. ;| Channel = 0-4                                                             |
  305. ;| ------------------------------------------------------------------------- |
  306. ;| Returns: -1 if DMA transaction completed                                  |
  307. ;|         (Maybe it returns the number of bytes left to transfer?)          |
  308. ;| dma_errno == 0 if no error, otherwise equals error number                 |
  309. ;+---------------------------------------------------------------------------+
  310. PROC _dma_done FAR
  311. ARG Channel:Word
  312.     push bp
  313.         mov  bp,sp
  314.         pushf
  315.         push dx
  316.         cmp  [Channel],3
  317.          jbe @@OkChannel
  318.         mov  ax,-1
  319.         mov  [_dma_errno],0Ch
  320.          jmp @@Exit_Pt
  321. @@OkChannel:
  322.         mov  dx,[Channel]
  323.         shl  dx,1
  324.         add  dx,count
  325.         cli
  326.         in   al,dx
  327.         mov  ah,al
  328.         in   al,dx
  329.         xchg al,ah
  330. @@Exit_Pt:
  331.         pop  dx
  332.         popf
  333.         pop  bp
  334.         ret
  335. ENDP _dma_done
  336. END
  337.